import errMagFun from "./errMsg";
const changeStateFun = (_this) => (str, ...value) => {
    if (!str || !_this.listState[str]) return errMagFun('loaded', str)
    try {
        return _this.listState[str](...value)
    } catch { }

}
const asyncChangeStateFun = (_this) => async (str, ...value) => {
    if (typeof str !== 'string' || str.length === 0) throw 'The first argument to asyncChangeState can only be a string of non-zero length'
    if (!_this.function_that_requires_asynchronous_processing[str]) {
        _this.function_that_requires_asynchronous_processing[str] = {}
        _this.function_that_requires_asynchronous_processing[str]._promise = new Promise(resolve => {
            _this.function_that_requires_asynchronous_processing[str]._resolve = resolve
        })
    }
    const result = await _this.function_that_requires_asynchronous_processing[str]._promise
    return result(...value)
}

const asyncPushStateFun = (_this) => (str, fun) => {
    if (typeof str !== 'string' || str.length === 0) throw 'The first argument to asyncPushState can only be a string of non-zero length'
    if (typeof fun !== 'function') throw 'The second argument to asyncPushStateFun must be a function'
    if (_this.function_that_requires_asynchronous_processing[str] && _this.function_that_requires_asynchronous_processing[str]._resolve) {
        _this.function_that_requires_asynchronous_processing[str]._resolve(fun)
    } else {
        _this.function_that_requires_asynchronous_processing[str] = {
            _promise: fun
        }
    }

}
const pushStateFun = (_this) => (str, fun) => {
    if (!typeof fun === 'function') return errMagFun('fnc', fun)
    _this.listState[str] = fun
}
const clearMethodsFun = (_this) => (methodKeys = [], isAsync) => {
    if (!(methodKeys instanceof Array)) return errMagFun('clearMethodsNoArr', methodKeys)
    if (methodKeys.length === 0) return errMagFun('clearMethodsEmpty');
    const methods = isAsync ? _this.function_that_requires_asynchronous_processing : _this.listState
    const methodsKeys = Object.keys(methods)
    methodKeys.forEach(item => {
        if (typeof item !== 'string') throw 'The argument to clearMethods  must be an array string'
        if (methodsKeys.indexOf(item) !== -1) delete (methods[item])
    })
}
const mapListStateFun = (_this) => (strArr = [], _instance) => {
    if (!strArr instanceof Array) return errMagFun('mapListStateNoArr', strArr)
    if (strArr.length === 0) return errMagFun('mapListStateEmpty')
    strArr.forEach(item => {
        if (typeof item !== 'string') throw 'The mapListState argument must be an array string'
        _instance[item] = (...value) => {
            new Proxy(_this.listState, {
                get(obj) {
                    return obj[item] ? obj[item] : errMagFun('loaded', item)
                }
            })[item](...value)
        }
    })
}
const creatPoxyListState = (_this) => {
    return new Proxy({}, {
        get(obj, key) {
            return obj[key]
        },
        set(obj, prop, value) {
            if (obj[prop]) {
                errMagFun('repetition', prop)
            } else {
                obj[prop] = value
            }
            return true
        },
        deleteProperty(obj, prop) {
            return delete (obj[prop])
        }

    })
}

export default (_this, options) => {
    if (!options) return
    _this.function_that_requires_asynchronous_processing = {}
    _this.listState = creatPoxyListState(_this)
    _this.clearMethods = clearMethodsFun(_this)
    _this.changeState = changeStateFun(_this)
    _this.pushState = pushStateFun(_this)
    _this.asyncChangeState = asyncChangeStateFun(_this)
    _this.asyncPushState = asyncPushStateFun(_this)
    _this.mapListState = mapListStateFun(_this)
}
